/* axis.cpp */

#include <cairomm/cairomm.h>

#include <dodo_plot/widget/axis.h>
#include <dodo_plot/widget/label.h>
#include <dodo_plot/kernel/canvas.h>
#include <dodo_plot/kernel/plotter.h>
#include <dodo_plot/kernel/basic_elements.h>
#include <dodo_plot/kernel/basic_utils.h>
#include <dodo_plot/projector/null_projector.h>

#include <iostream>

namespace dodo_plot
{

Axis::Axis(double min_val, double max_val,
	double tick_interval, double ref_val,
	int minor_tick_count,
	int mode)
	:
		line_width_(0.5),
		line_color_(color_name::BLACK),
		unit_(""),
		tick_length_(8.0),
		minor_tick_length_(5.0),
		label_font_size_(12),
		label_font_color_(color_name::BLACK),
		label_distance_(15)
{
	apply_mode(mode);
	fill_data(min_val, max_val, 
		tick_interval, ref_val,
		minor_tick_count,
		to_string<double>
		);
}

Axis::Axis(double min_val, double max_val,
	double tick_interval, double ref_val,
	int minor_tick_count,
	const std::string& unit,
	int mode)
	:
		line_width_(0.5),
		line_color_(color_name::BLACK),
		unit_(unit),
		tick_length_(8.0),
		minor_tick_length_(5.0),
		label_font_size_(12),
		label_font_color_(color_name::BLACK),
		label_distance_(15)
{
	apply_mode(mode);
	fill_data(min_val, max_val, 
		tick_interval, ref_val,
		minor_tick_count,
		to_string<double>
		);
}

void Axis::set_mode(int mode)
{
	apply_mode(mode);
}

void Axis::set_line_width(double width)
{
	line_width_ = width;
}

void Axis::set_line_color(const Color& color)
{
	line_color_ = color;
}

void Axis::set_unit(const std::string& unit)
{
	unit_ = unit;
}

void Axis::set_tick_length(double length)
{
	tick_length_ = length;
}

void Axis::set_minor_tick_length(double length)
{
	minor_tick_length_ = length;
}

void Axis::set_font_size(double size)
{
	label_font_size_ = size;
}

void Axis::set_font_color(const Color& color)
{
	label_font_color_ = color;
}

void Axis::set_label_distance(double distance)
{
	label_distance_ = distance;
}

void Axis::set_label_align_mode(int mode)
{
	label_align_mode_ = mode;
}

Axis::const_pos_iterator Axis::tick_begin() const
{
	return pos_.begin();
}

Axis::const_pos_iterator Axis::tick_end() const
{
	return pos_.end();
}

double Axis::local_min() const
{
	return 0.0;
}

double Axis::local_max() const
{
	return 1.0;
}

Color Axis::get_line_color() const
{
	return line_color_;
}

double Axis::get_line_width() const
{
	return line_width_;
}

void Axis::draw(const Plotter& plotter) const
{
	plotter.save();
	plotter.begin_new_path();

	plotter.set_color(line_color_);
	plotter.set_line_width(line_width_);

	double main_line_start_x;
	double main_line_end_x;
	double main_line_start_y;
	double main_line_end_y;

	double tick_x_offset;
	double tick_y_offset;
	double minor_tick_x_offset;
	double minor_tick_y_offset;
	double label_x_offset;
	double label_y_offset;

	if(horizontal_)
	{
		main_line_start_x = 0;
		main_line_end_x = 1;
		main_line_start_y = 0;
		main_line_end_y = 0;
		tick_x_offset = 0;
		tick_y_offset = tick_length_ * tick_unit_;
		minor_tick_x_offset = 0;
		minor_tick_y_offset = minor_tick_length_ * tick_unit_;
		label_x_offset = 0;
		label_y_offset = label_distance_ * tick_unit_;
	}
	else
	{
		main_line_start_x = 0;
		main_line_end_x = 0;
		main_line_start_y = 1;
		main_line_end_y = 0;
		tick_y_offset = 0;
		tick_x_offset = tick_length_ * tick_unit_;
		minor_tick_y_offset = 0;
		minor_tick_x_offset = minor_tick_length_ * tick_unit_;
		label_y_offset = 0;
		label_x_offset = label_distance_ * tick_unit_;
	}

	plotter.move_to(main_line_start_x, main_line_start_y);
	plotter.line_to(main_line_end_x, main_line_end_y);
	plotter.stroke();

	Label label("", label_font_size_, label_align_mode_);
	label.set_color(label_font_color_);

	for(int i = 0; i < pos_.size(); ++i)
	{
		Point start(pos_[i], pos_[i]);
		plotter.move_to(start.x, start.y);
		plotter.abs_rel_line_to(tick_x_offset, tick_y_offset);
		plotter.stroke();

		label.set_text(str_labels_[i] + unit_);
		
		Point abs_point = plotter.get_abs_point(start);
		abs_point.x += label_x_offset;
		abs_point.y += label_y_offset;

		label.draw(
			plotter.get_cr(),
			abs_point
			);
	}

	for(int i = 0; i < minor_pos_.size(); ++i)
	{
		Point start(minor_pos_[i], minor_pos_[i]);
		plotter.move_to(start.x, start.y);
		plotter.abs_rel_line_to(minor_tick_x_offset, minor_tick_y_offset);
		plotter.stroke();
	}

	plotter.restore();
}

void Axis::apply_mode(int mode)
{
	switch(mode)
	{
	case LEFT:
		tick_unit_ = -1.0;
		horizontal_ = false;
		label_align_mode_ = RIGHT;
		break;
	case RIGHT:
		tick_unit_ = 1.0;
		horizontal_ = false;
		label_align_mode_ = LEFT;
		break;
	case TOP:
		tick_unit_ = -1.0;
		horizontal_ = true;
		label_align_mode_ = CENTER;
		break;
	default:
		tick_unit_ = 1.0;
		horizontal_ = true;
		label_align_mode_ = CENTER;
	}
}

}
